﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace YY.DataLinq
{
    public static class ObjectConverter
    {
        private class CommonProperty
        {
            public PropertyInfo SourceProperty { get; set; }
            public PropertyInfo TargetProperty { get; set; }
        }

        public static T Cast<T>(this object o, T t)
        {
            return (T)o;
        } 

        public static List<TResult> ConvertTo<TResult>(this IEnumerable source)
            where TResult : new()
        {
            if (source == null) //啥都不用干
                return null;

            if (source is IEnumerable<TResult>)
                return source.Cast<TResult>().ToList();//源类型于目标类型一致，可以直接转换

            List<TResult> result = new List<TResult>();
            bool hasGetElementType = false;
            IEnumerable<CommonProperty> commonProperties = null; //公共属性(按属性名称进行匹配)

            foreach (var s in source)
            {
                if (!hasGetElementType) //访问第一个元素时，取得属性对应关系；后续的元素就不用再重新计算了
                {
                    if (s is TResult) //如果源类型是目标类型的子类，可以直接Cast<T>扩展方法
                    {
                        return source.Cast<TResult>().ToList();
                    }
                    commonProperties = GetCommonProperties(s.GetType(), typeof(TResult));
                    hasGetElementType = true;
                }

                TResult t = new TResult();
                foreach (CommonProperty commonProperty in commonProperties) //逐个属性拷贝
                {
                    object value = commonProperty.SourceProperty.GetValue(s, null);
                    commonProperty.TargetProperty.SetValue(t, value, null);
                }
                result.Add(t);
            }

            return result;
        }

        private static IEnumerable<CommonProperty> GetCommonProperties(Type sourceType, Type targetType)
        {
            PropertyInfo[] sourceTypeProperties = sourceType.GetProperties();//获取源对象所有属性
            PropertyInfo[] targetTypeProperties = targetType.GetProperties(); //获取目标对象所有属性
            return from SP in sourceTypeProperties
                   join TP in targetTypeProperties
                      on SP.Name.ToLower() equals TP.Name.ToLower() //根据属性名进行对应(不区分大小写)
                   select new CommonProperty
                   {
                       SourceProperty = SP,
                       TargetProperty = TP
                   };
        }
    }
}
